package com.rws.monitoring;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;

/**
 * 简单的lock锁监听器
 * examine()方法打断生效的线程
 *  ThreadInfo的overdue方法中定义的失效条件是1000 * 10毫秒，其他策略待开发
 */
public final class DateControlMonitor implements ControlMonitor{

    static {
        new Thread(()->{
            examine();
        }).start();
    }

    private static final Map<Lock,List<ThreadInfo>> lockMap = new ConcurrentHashMap<>();

    public static void examine(){
        while (true){
            CountDownLatch count = new CountDownLatch(1);
            Timer timer = new Timer();
            CountDownLatch finalCount = count;
            timer.schedule(new TimerTask() {
                public void run() {
                    if(!lockMap.isEmpty()){
                        lockMap.forEach((k,v)->{
                            for (ThreadInfo threadInfo : v) {
                                if(threadInfo.overdue()){
                                    interrupt(threadInfo.getThread());
                                }
                            }
                        });
                    }
                    finalCount.countDown();
                }
            }, 1000);// 设定指定的时间time为1000毫秒
            try {
                count.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            count = null;
        }
    }

    @Override
    public void register(Lock lock, Thread currentThread) {
        List<ThreadInfo> threadInfos = lockMap.get(lock);
        if(threadInfos == null){
            synchronized (DateControlMonitor.class){
                threadInfos = lockMap.get(lock);
                if(threadInfos == null){
                    threadInfos = new CopyOnWriteArrayList<>();
                }
            }
        }
        threadInfos.add(createThreadInfo(lock, currentThread));
        lockMap.put(lock,threadInfos);
    }

    @Override
    public void release(Lock lock, Thread currentThread) {
        List<ThreadInfo> threadInfos = lockMap.get(lock);
        if(threadInfos == null){
            return;
        }
        threadInfos.remove(currentThread);
    }

    public static void interrupt(Thread thread) {
        thread.interrupt();
    }

    protected ThreadInfo createThreadInfo(Lock lock, Thread thread){
        return new ThreadInfo(lock,thread);
    }

    class ThreadInfo{

        final Lock lock;
        final Thread thread;

        final long createTime;

        public ThreadInfo(Lock lock,Thread thread){
            this.lock = lock;
            this.thread = thread;
            this.createTime = System.currentTimeMillis();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ThreadInfo that = (ThreadInfo) o;
            return Objects.equals(thread, that.thread);
        }

        @Override
        public int hashCode() {
            return Objects.hash(thread);
        }

        /**
         * 过期返回true
         * @return
         */
        public boolean overdue(){
            return (System.currentTimeMillis() - createTime) > 1000 * 10;
        }

        public Thread getThread() {
            return thread;
        }
    }
}
